// Fundermental Unit Test Framework

#include "../../../Assembly/System.Test.hpp"
#include "../../../Assembly/System.Math.hpp"

TestOption(exception, on);  // throw exception message box to debugger, on/off
TestOption(output, on);     // output results to the console, on/off
TestTimeout(5.00);          // timeout in nightly, in seconds; remove this line for infinite timeout

using namespace System::Math;
using namespace System::Collections::Generic;


int k = 0;

void PermutationTest(int *indices, int begin_index, int end_index, ref<List<arrayref<Byte>>> all_lists)
{
	if (begin_index == end_index)
	{
		arrayref<Byte> digit_list = gcnew Byte[9];
		for (int i = 0; i <= end_index; i++)
		{
			digit_list[i] = indices[i];
		}
		all_lists->Add(digit_list);

		k++;
		if (k > 362870)
		{
			int b = 1;
		}
	}
	else
	{
		for (int j = begin_index; j <= end_index; j++)
		{
			Math::Swap(indices[j], indices[begin_index]);
			PermutationTest(indices, begin_index + 1, end_index, all_lists);
			Math::Swap(indices[j], indices[begin_index]);
		}
	}
}

int getFactorial(int num)
{
	if (num == 1)
		return 1;
	else
		return num * getFactorial(num - 1);
}

TestCase
{
	int count = 9;
	int *indices = new int[count];
	for (int i = 0; i < count; i++)
		indices[i] = i;
	ref<List<arrayref<Byte>>> all_list = gcnew List<arrayref<Byte>>();

	PermutationTest(indices, 0, count - 1, all_list);

	vec2 coordinate_array[9];

	coordinate_array[0] = vec2(-1, 1);
	coordinate_array[1] = vec2(0, 1);
	coordinate_array[2] = vec2(1, 1);
	coordinate_array[3] = vec2(-1, 0);
	coordinate_array[4] = vec2(0, 0);
	coordinate_array[5] = vec2(1, 0);
	coordinate_array[6] = vec2(-1, -1);
	coordinate_array[7] = vec2(0, -1);
	coordinate_array[8] = vec2(1, -1);

	double distance = 0.0;
	double max_distance = distance;
	ref<List<arrayref<Byte>>> max_distance_list = gcnew List<arrayref<Byte>>();


	for (int i = 0; i < getFactorial(count); i++)
	{
		arrayref<Byte> path = gcnew Byte[9];

		path = all_list->ToArray()[i];

		distance = (coordinate_array[path[0]] - coordinate_array[path[1]]).GetLength()
			+ (coordinate_array[path[1]] - coordinate_array[path[2]]).GetLength()
			+ (coordinate_array[path[2]] - coordinate_array[path[3]]).GetLength()
			+ (coordinate_array[path[3]] - coordinate_array[path[4]]).GetLength()
			+ (coordinate_array[path[4]] - coordinate_array[path[5]]).GetLength()
			+ (coordinate_array[path[5]] - coordinate_array[path[6]]).GetLength()
			+ (coordinate_array[path[6]] - coordinate_array[path[7]]).GetLength()
			+ (coordinate_array[path[7]] - coordinate_array[path[8]]).GetLength();

		if (distance > max_distance)
		{
			max_distance = distance;
			max_distance_list->Clear();
			max_distance_list->Add(path.ToArray());
		}
		else if(distance == max_distance)
		{
			max_distance_list->Add(path.ToArray());
		}
		else
		{
			continue;
		}
	}

	for (int i = 0; i < max_distance_list->Count; i++)
	{
		for (int j = 0; j < count; j++)
			Console::Write((max_distance_list->ToArray()[i])[j] + 1);

		Console::WriteLine();
	}
};
